#include "stdafx.h"

#include "ingdirect_it.hpp"
#include <iostream>
#include <fstream>
#include <iterator>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>

namespace po = boost::program_options; 
using namespace std;

const char* ingdirect_it::DEFAULT_INGDIRECT_PINPAD_COORDS_REGEX = "\\s+";
const std::string ingdirect_it::DEFAULT_INGDIRECT_PINPAD_COORDS_SEP = "§";

// A helper function to simplify the main part.
template<class T>
ostream& operator<<(ostream& os, const vector<T>& v)
{
    copy(v.begin(), v.end(), ostream_iterator<T>(cout, " ")); 
    return os;
}

std::ostream& operator<<(std::ostream& ost, const ingdirect_it& c)
{
	ost << "use ingdirect pinpad coordinates = " << c.use_ingdirect_pinpad_coords << "\n";
	ost << "ingdirect pinpad coordinates regex = " << c._ingdirect_pinpad_coords_regex << "\n";
	ost << "config filename = " << c._config_filename << "\n";
	ost << "ingdirect pinpad coordinates = " << c.ingdirect_pinpad_coords << "\n";
	ost << "ingdirect pinpad coordinates separator = " << c.ingdirect_pinpad_coords_sep << "\n";

	return ost;
}

const char* ingdirect_it::CONFIG_OPTS[ingdirect_it::CONFIG_TOT_OPTS][2] = 
{	
	{"use-ingdirect-pinpad-coords", "use ingdirect pinpad coordinates"}
};

const char* ingdirect_it::HIDDEN_OPTS[ingdirect_it::HIDDEN_TOT_OPTS][2] =
{
	{"ingdirect-pinpad-coords","ingdirect pinpad coordinates"},
	{"ingdirect-pinpad-coords-separator","ingdirect separator between pinpad coordinates"},
	{"ingdirect-pinpad-coords-regex","ingdirect regex for pinpad coordinates"}
};


ingdirect_it::ingdirect_it(const char* _filename)
{	
	_config_filename = _filename;

	try {   

		if(_config_filename.empty())
		{
			throw ("config file has to be specified: -c /path_to_config/filename"); 
		}

        // Declare a group of options that will be 
        // allowed both on command line and in
        // config file
#ifdef WIN32
        po::options_description config("Configuration");
#else
	po::options_description config("Configuration", po::options_description::m_default_line_length*2);
#endif
        config.add_options()
		(CONFIG_OPTS[ingdirect_it::USE_INGDIRECT_PINPAD_COORDS][0], po::value<bool>(&use_ingdirect_pinpad_coords)->default_value(false), CONFIG_OPTS[ingdirect_it::USE_INGDIRECT_PINPAD_COORDS][1])
        ;

        // Hidden options, will be allowed both on command line and
        // in config file, but will not be shown to the user.
        po::options_description hidden("Hidden options");
        hidden.add_options()            
		(HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS][0], po::value<std::string>(), HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS][1])
		(HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_SEP][0], po::value<std::string>(&ingdirect_pinpad_coords_sep)->default_value(ingdirect_it::DEFAULT_INGDIRECT_PINPAD_COORDS_SEP), HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_SEP][1])
		(HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_REGEX][0], po::value<std::string>(&_ingdirect_pinpad_coords_regex)->default_value(ingdirect_it::DEFAULT_INGDIRECT_PINPAD_COORDS_REGEX), HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_REGEX][1])
        ;

        po::options_description config_file_options;
        config_file_options.add(config).add(hidden);
      
        po::variables_map vm;

	ifstream ifs(_filename);
	if(ifs.bad()) throw ("config file not found: " + _config_filename);


    	store(parse_config_file(ifs, config_file_options), vm);
    	notify(vm);           	
	
	if(!vm[CONFIG_OPTS[ingdirect_it::USE_INGDIRECT_PINPAD_COORDS][0]].empty())
	{
		use_ingdirect_pinpad_coords = vm[CONFIG_OPTS[ingdirect_it::USE_INGDIRECT_PINPAD_COORDS][0]].as < bool >();
	}

	if(!vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS][0]].empty())
    {
                std::string input(vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS][0]].as< std::string>());
                boost::regex expression(vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_REGEX][0]].as< std::string>() );
                       
		boost::regex_split(std::back_inserter(ingdirect_pinpad_coords), input, expression); 
				
    }

	if(!vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_REGEX][0]].empty())
	{
		_ingdirect_pinpad_coords_regex	= vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_REGEX][0]].as< std::string >();
	}

	if(!vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_SEP][0]].empty())
	{
	  	ingdirect_pinpad_coords_sep = vm[HIDDEN_OPTS[ingdirect_it::INGDIRECT_PINPAD_COORDS_SEP][0]].as< std::string >();
	}
	

    }
    catch(exception& e)
    {
		cout << e.what() << std::endl;
    }       

}


ingdirect_it& ingdirect_it::operator=(ingdirect_it const& _cfg)
{
	use_ingdirect_pinpad_coords = _cfg.use_ingdirect_pinpad_coords;
	_ingdirect_pinpad_coords_regex = _cfg._ingdirect_pinpad_coords_regex;
	ingdirect_pinpad_coords_sep = _cfg.ingdirect_pinpad_coords_sep;	
	ingdirect_pinpad_coords = _cfg.ingdirect_pinpad_coords;
	
	return *this;
}

std::vector<std::string> const& ingdirect_it::get_ingdirect_pinpad_coords()
{
	return ingdirect_pinpad_coords;
}

std::string const& ingdirect_it::get_ingdirect_pinpad_coords_regex()
{
	return _ingdirect_pinpad_coords_regex;
}

const string& ingdirect_it::get_ingdirect_pinpad_coords_sep()
{
	return ingdirect_pinpad_coords_sep;
}

bool& ingdirect_it::get_use_ingdirect_pinpad_coords()
{
	return use_ingdirect_pinpad_coords;
}
